package com.xdl.moudle.utils.util;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Authenticator;
import java.net.HttpURLConnection;
import java.net.PasswordAuthentication;
import java.net.Proxy;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;

import javax.activation.MimetypesFileTypeMap;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.servlet.http.HttpServletRequest;

public class HttpUtil {
    
//    public static String dataFormat = "yyyyMMddHHmmssS";
    
	public static String post(String url,int timeOut) throws Exception{
        return post(url,null,null,null,false,timeOut);
	}
	
    public static String post(String url,String json) throws Exception{
         return post(url,json,null,null,false,null);
    }
    public static String post(String url,Map<String,Object> params) throws Exception{
    	String json = prepareParam(params);
    	return post(url, json, null, null, false, null);
    }
    public static String post(String url,TreeMap<String,String> params) throws Exception{
    	return post(url,null,params,null,false,null);
    }
    
    public static String post(String url,String json,Map<String,String> headers,boolean ssl) throws Exception{
    	return post(url,json,null,headers,ssl,null);
    }
    
    public static String post(String url, InputStream is) throws Exception {
        URL u = new URL(url);
        InputStream inS = null;
        OutputStream onS = null;
        HttpURLConnection connection = null;
        try {
            connection = (HttpURLConnection) u.openConnection();
            connection.setConnectTimeout(30000);
            connection.setReadTimeout(30000);
            connection.setDoOutput(true);
            onS = connection.getOutputStream();
            if (is != null) inS = is;
            int reading;
            byte[] buffer = new byte[1024];
            do {
                reading = inS.read(buffer);
                if (reading > 0) {
                    onS.write(buffer, 0, reading);
                }
            } while (reading >= 0);
            inS.close();

            if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
                inS = connection.getInputStream();
                byte[] resp = new byte[0];
                buffer = new byte[1024];
                do {
                    reading = inS.read(buffer, 0, buffer.length);
                    if (reading > 0) {
                        byte[] content = new byte[resp.length + reading];
                        System.arraycopy(resp, 0, content, 0, resp.length);
                        System.arraycopy(buffer, 0, content, resp.length, reading);
                        resp = content;
                    }
                } while (reading >= 0);
                String ret = new String(resp, "UTF-8");
                return ret;
            } else {
                throw new Exception(String.valueOf(connection.getResponseCode()) + " : " + url);
            }
        } catch (Exception e) {
            throw e;
        } finally {
            if (inS != null)
                inS.close();
            if (onS != null)
                onS.close();
        }
    }
    
    public static String post(String url,String json,TreeMap<String,String> params,Map<String,String> headers,boolean ssl,Integer timeOut) throws Exception{
    	if(ssl)
    		trustAllHttpsCertificates();
    	
    	if(timeOut == null){
    		timeOut = 30000;
    	}
    	
    	String paramStr = prepareParamInOrder(params);
        if(paramStr == null || paramStr.trim().length()<1){
        }else{
            url +="?"+paramStr;
        }
        URL u = new URL(url);
        
        InputStream inS = null;
        OutputStream onS = null;
        HttpURLConnection connection = null;
        try{
            connection = (HttpURLConnection)u.openConnection();
            connection.setConnectTimeout(timeOut);
            connection.setReadTimeout(timeOut);
            connection.setDoOutput(true);
            if(headers!=null){
            	for(String headerKey:headers.keySet())
            		connection.setRequestProperty(headerKey, headers.get(headerKey));
            }
            onS = connection.getOutputStream();
            if(json!=null)
            	onS.write( json.getBytes("UTF-8"));
            if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
                inS = connection.getInputStream();
                int reading;
                byte[] resp = new byte[0];
                byte[] buffer = new byte[1024];
                do{
                    reading = inS.read(buffer, 0, buffer.length);
                    if (reading>0) {
                        byte[] content = new byte[resp.length+reading];
                        System.arraycopy(resp, 0, content, 0, resp.length);
                        System.arraycopy(buffer, 0, content, resp.length, reading);
                        resp = content;
                    }
                }while(reading>=0);
                String ret =  new String(resp,"UTF-8");
                return ret;
            }
            else{
                throw new Exception(String.valueOf(connection.getResponseCode())+" : "+url);
            }
        }catch(Exception e){
            throw e;
        }finally{
            if(inS!=null)
                inS.close();
            if(onS!=null)
                onS.close();
            if(connection!=null){
            	connection.disconnect();
            }
        }
    } 
    
	public static String get(String url,final String user,final String passwd) throws Exception{
    	 Authenticator.setDefault(new Authenticator(){
    		 @Override
    		 public PasswordAuthentication getPasswordAuthentication() {
    			 return (new PasswordAuthentication(user, passwd.toCharArray()));
    		 }
    	 });
    	 return get(url);
    }
    
	private static String prepareParamInOrder(TreeMap<String,String> paramMap) throws Exception{
        StringBuffer sb = new StringBuffer();
        if(paramMap==null||paramMap.isEmpty()){
            return "" ;
        }else{
            for(String key: paramMap.keySet()){
                String value = (String)paramMap.get(key);
            	value = URLEncoder.encode((String)value,"UTF-8");
                if(sb.length()<1){
                    sb.append(key).append("=").append(value);
                }else{
                    sb.append("&").append(key).append("=").append(value);
                }
            }
            return sb.toString();
        }
    }
	
	private static String prepareParam(Map<String,Object> paramMap) throws Exception{
        StringBuffer sb = new StringBuffer();
        if(paramMap==null||paramMap.isEmpty()){
            return "" ;
        }else{
            for(String key: paramMap.keySet()){
                Object value = paramMap.get(key);
                if(value == null)
                	continue;
                if(value instanceof String){
                	value = URLEncoder.encode((String)value,"UTF-8");
                }
                if(sb.length()<1){
                    sb.append(key).append("=").append(value);
                }else{
                    sb.append("&").append(key).append("=").append(value);
                }
            }
            return sb.toString();
        }
    }
    
    public static String get(String url) throws Exception{
        return _get(url,null,false,null);
    }
    
    public static String get(String url,Map<String,Object> params) throws Exception{
    	String paramStr = prepareParam(params);
        return _get(url,paramStr,false,null);
    }
    
    public static String get(String url,Map<String,Object> params,Integer timeout) throws Exception{
    	String paramStr = prepareParam(params);
        return _get(url,paramStr,false,timeout);
    }
    
    public static String getByParamsOrdered(String url,TreeMap<String,String> params,boolean ssl,Integer timeout) throws Exception{
        String paramStr = prepareParamInOrder(params);
        return _get(url,paramStr,ssl,timeout);

    }
    
    public static String get(String url,Map<String,Object> params,boolean ssl,Integer timeout) throws Exception{
        String paramStr = prepareParam(params);
        return _get(url,paramStr,ssl,timeout);
    }
    
    private static String _get(String url,String paramStr,boolean ssl,Integer timeout) throws Exception{
    	if(ssl)
    		trustAllHttpsCertificates();
    	
    	if(timeout==null){
    		timeout = 30000;
    	}
        
        if(paramStr == null || paramStr.trim().length()<1){
        }else{
            url +="?"+paramStr;
        }
        
        URL u = new URL(url);
        InputStream inS = null;
        HttpURLConnection connection = null;
        try{
            connection = (HttpURLConnection)u.openConnection();
            connection.setConnectTimeout(timeout);
            connection.setReadTimeout(timeout);
            if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
                
                inS = connection.getInputStream();
                int reading;
                byte[] resp = new byte[0];
                byte[] buffer = new byte[1024];
                do{
                    reading = inS.read(buffer, 0, buffer.length);
                    if (reading>0) {
                        byte[] content = new byte[resp.length+reading];
                        System.arraycopy(resp, 0, content, 0, resp.length);
                        System.arraycopy(buffer, 0, content, resp.length, reading);
                        resp = content;
                    }
                }while(reading>=0);
                String ret =  new String(resp,"UTF-8");
                return ret;
            }
            else{
                throw new Exception(String.valueOf(connection.getResponseCode())+" : "+url);
            }
        }catch(Exception e){
            throw e;
        }finally{
            if(inS!=null)
                inS.close();
            if(connection!=null){
            	connection.disconnect();
            }
        }
    }
    
    public static String getRealURL(String url) throws Exception{
    	HttpURLConnection connection = null;
    	try{
    		URL u = new URL(url);
            connection = (HttpURLConnection)u.openConnection();
            connection.setConnectTimeout(30000);
            connection.setReadTimeout(30000);
            if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
                return connection.getURL().toString();
            }
            else{
                return null;
            }
    	}finally{
    		if(connection!=null)
    			connection.disconnect();
    	}
        
    }
    
    public static String getContent(String url,String encoding) throws Exception{
        return getContent(url, encoding,null);
    }
    
    public static String getContent(String url,String encoding,Proxy proxy) throws Exception{
        URL u = new URL(url);
        InputStream inS = null;
        HttpURLConnection connection = null;
        try{
	        if(proxy!=null)
	        	connection = (HttpURLConnection)u.openConnection(proxy);
	        else
	        	connection = (HttpURLConnection)u.openConnection();
	        
	        connection.setConnectTimeout(30000);
	        connection.setReadTimeout(30000);
	        if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
	            inS = connection.getInputStream();
	            int reading;
	            byte[] resp = new byte[0];
	            byte[] buffer = new byte[1024];
	            do{
	                reading = inS.read(buffer, 0, buffer.length);
	                if (reading>0) {
	                    byte[] content = new byte[resp.length+reading];
	                    System.arraycopy(resp, 0, content, 0, resp.length);
	                    System.arraycopy(buffer, 0, content, resp.length, reading);
	                    resp = content;
	                }
	            }while(reading>=0);
	            inS.close();
	            return new String(resp,encoding==null?"UTF-8":encoding);
	        }
	        else{
	            return null;
	        }
        }catch(Exception e){
        	throw e;
        }finally{
        	if(inS!=null)
        		inS.close();
        	if(connection!=null)
        		connection.disconnect();
        }
    }
    
    public static void downloadFile(String remoteUrl,File localFileToSave) throws Exception {
        // 下载网络文件
        int byteread = 0;

        InputStream is = null;
        OutputStream os = null;
        try {
            URL url = new URL(remoteUrl);
            URLConnection conn = url.openConnection();
            conn.setConnectTimeout(30000);
            conn.setReadTimeout(30000);
            is = conn.getInputStream();
            os = new FileOutputStream(localFileToSave);

            byte[] buffer = new byte[1024*1024];
            while ((byteread = is.read(buffer)) != -1) {
                os.write(buffer, 0, byteread);
            }
        } catch (Exception e) {
            throw e;
        }finally{
            if(is!=null)
                is.close();
            if(os!=null)
                os.close();
        }
    }
    
    public static byte[] read(String url) throws Exception {
        URL u = new URL(url);
        InputStream inS = null;
        HttpURLConnection connection = null;
        try{
            connection = (HttpURLConnection)u.openConnection();
            connection.setConnectTimeout(30000);
            connection.setReadTimeout(30000);
            if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
                
                inS = connection.getInputStream();
                int reading;
                byte[] resp = new byte[0];
                byte[] buffer = new byte[1024];
                do{
                    reading = inS.read(buffer, 0, buffer.length);
                    if (reading>0) {
                        byte[] content = new byte[resp.length+reading];
                        System.arraycopy(resp, 0, content, 0, resp.length);
                        System.arraycopy(buffer, 0, content, resp.length, reading);
                        resp = content;
                    }
                }while(reading>=0);
                return resp;
            }
            else{
                throw new Exception(String.valueOf(connection.getResponseCode())+" : "+url);
            }
        }catch(Exception e){
            throw e;
        }finally{
            if(inS!=null)
                inS.close();
            if(connection!=null)
            	connection.disconnect();
        }
    }
    
    /**
     * 模拟Post提交数据和上传图片
     * @param urlStr
     * @param textMap
     * @param fileMap
     * @return
     * @throws IOException 
     */
    @SuppressWarnings("rawtypes")
    public static String postMultiForm(String urlStr, Map<String, String> textMap, Map<String, String> fileMap) throws IOException {  
        String res = "";
        HttpURLConnection conn = null;
        InputStream inS=null;
        OutputStream out=null;
        String BOUNDARY = "---------------------------123821742118716";//boundary就是request头和上传文件内容的分隔符  
        try {
            URL url = new URL(urlStr);
            conn = (HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(5000);
            conn.setReadTimeout(30000);
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Connection", "Keep-Alive");
            conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.6)");
            conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
  
            out = new DataOutputStream(conn.getOutputStream());
            // text value
            if (textMap != null) {
                StringBuffer strBuf = new StringBuffer();
                Iterator iter = textMap.entrySet().iterator();
                while (iter.hasNext()) {
                    Map.Entry entry = (Map.Entry) iter.next();
                    String inputName = (String) entry.getKey();
                    String inputValue = (String) entry.getValue();
                    if (inputValue == null) {
                        continue;
                    }  
                    strBuf.append("\r\n").append("--").append(BOUNDARY).append("\r\n");
                    strBuf.append("Content-Disposition: form-data; name=\""  
                            + inputName + "\"\r\n\r\n");
                    strBuf.append(inputValue);
                }  
                out.write(strBuf.toString().getBytes());
            }  
  
            // file  
            if (fileMap != null) {  
                Iterator iter = fileMap.entrySet().iterator();
                while (iter.hasNext()) {  
                    Map.Entry entry = (Map.Entry) iter.next();
                    String inputName = (String) entry.getKey();
                    String inputValue = (String) entry.getValue();
                    if (inputValue == null) {  
                        continue;
                    }  
                    File file = new File(inputValue);
                    String filename = file.getName();
                    String contentType = new MimetypesFileTypeMap().getContentType(file);
                    if (filename.endsWith(".png")) {  
                        contentType = "image/png";
                    } else if (filename.endsWith(".gif")) {
                        contentType = "image/gif";
                    } else if (filename.endsWith(".jpg")) {
                        contentType = "image/jpeg";
                    }
                    if (contentType == null || contentType.equals("")) {  
                        contentType = "application/octet-stream";
                    }  
  
                    StringBuffer strBuf = new StringBuffer();
                    strBuf.append("\r\n").append("--").append(BOUNDARY).append("\r\n");
                    strBuf.append("Content-Disposition: form-data; name=\""  
                            + inputName + "\"; filename=\"" + filename + "\"\r\n");
                    strBuf.append("Content-Type:" + contentType + "\r\n\r\n");
  
                    out.write(strBuf.toString().getBytes());
  
                    DataInputStream in = new DataInputStream(  
                            new FileInputStream(file));
                    int bytes = 0;
                    byte[] bufferOut = new byte[1024];
                    while ((bytes = in.read(bufferOut)) != -1) {  
                        out.write(bufferOut, 0, bytes);
                    }  
                }  
            }  
  
            byte[] endData = ("\r\n--" + BOUNDARY + "--\r\n").getBytes();
            out.write(endData);
            out.flush();
  
            // 读取返回数据  
            StringBuffer strBuf = new StringBuffer();
            inS = conn.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(inS));
            String line = null;
            while ((line = reader.readLine()) != null) {  
                strBuf.append(line).append("\n");
            }  
            res = strBuf.toString();
            reader.close();
            reader = null;
        } catch (Exception e) {  
            System.out.println("发送POST请求出错。" + urlStr);
            e.printStackTrace();
        } finally {  
        	if(out!=null){
        		out.close();
        	}
        	if(inS!=null){
        		inS.close();
        	}
            if (conn != null) {  
                conn.disconnect();
                conn = null;
            }  
        }  
        return res;
    }
    
    public static String getRemoteIP(HttpServletRequest req){
    	String ip = req.getHeader("HTTP_X_REAL_IP");
    	if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
    		ip = req.getHeader("x-forwarded-for");
    	}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = req.getHeader("Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = req.getHeader("WL-Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = req.getRemoteAddr();
		}
		return ip;
	}
    
    private static boolean sslInit = false;
     
    private static void trustAllHttpsCertificates() throws NoSuchAlgorithmException, KeyManagementException{
    //  Create a trust manager that does not validate certificate chains:
    	if(!sslInit){
	        TrustManager[] trustAllCerts =
	                new javax.net.ssl.TrustManager[1];
	
	        TrustManager tm = new miTM();
	        trustAllCerts[0] = tm;
	        SSLContext sc =SSLContext.getInstance("SSL");

	        sc.init(null, trustAllCerts, null);

	        HttpsURLConnection.setDefaultSSLSocketFactory(
	                sc.getSocketFactory());
	        
	        HostnameVerifier hv = new HostnameVerifier() {
	            public boolean verify(String urlHostName, SSLSession session) {
	                System.out.println("Warning: URL Host: " + urlHostName + " vs. "
	                                   + session.getPeerHost());
	                return true;
	            }
	        };
	        HttpsURLConnection.setDefaultHostnameVerifier(hv);
    	}
    }
    
    private static class miTM implements javax.net.ssl.TrustManager,javax.net.ssl.X509TrustManager {
		public java.security.cert.X509Certificate[] getAcceptedIssuers() {
		    return null;
		}
		
		public boolean isServerTrusted(
		        java.security.cert.X509Certificate[] certs) {
		    return true;
		}
		
		public boolean isClientTrusted(
		        java.security.cert.X509Certificate[] certs) {
		    return true;
		}
		
		public void checkServerTrusted(
		        java.security.cert.X509Certificate[] certs, String authType) throws
		        java.security.cert.CertificateException {
		    return;
		}
		
		public void checkClientTrusted(
		        java.security.cert.X509Certificate[] certs, String authType) throws
		        java.security.cert.CertificateException {
		    return;
		}
    }

}
